#include "../../include/AuthHandler.hpp"
#include "../../include/AuthTypes.hpp"

// 生成一个随机的会话ID
// 每一个会话都会有一个对应的随机的会话ID
string AuthHandler::generateSessionId() {
	static const char alphannum[] = "0123456789"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz";
	const int len = 32;		// 限制会话ID长度
	string sid;
	sid.reserve(len);
	for (int i = 0; i < len; i++) {
		sid += alphannum[rand() % (sizeof(alphannum) - 1)];		// 随机数生成 字符
	}
	return sid;
}
// 构造函数，初始化AuthHandler 给一个赋值
AuthHandler::AuthHandler(DatabasePool& pool) : ApiHandler(pool) {}
// 注册路由封装
void AuthHandler::registerUser(const Request& req, Response& res) {
	try {
		// 解析请求参数
		Value params = parseRequest(req);
		// 必要参数  传入
		vector<string> required = {"username", "password", "email"};
		// 做一下校验
		if (!validateParams(params, required)) {
			return sendError(res, "缺少必要参数", 400);		// 返回错误
		}
		withTransaction([&](DBUtil::Transaction& trans) {
			// 事务处理数据库操作
			// auto conn = trans.getConnection();
			// 事务中已经管理了数据库连接。只需要使用 trans.executePrepared 来执行 SQL 语句。
			// 检查信息是否存在
			Value checkAns = trans.query("SELECT id FROM users WHERE username '" + params["username"].asString() + "' OR email = '" + params["email"].asString() + "'");
			if (!checkAns.empty()) {
				throw runtime_error("用户名或邮箱已存在");
			}
			// 现在就是没有存在已有用户的情况
			// 做注册
			int affected = trans.execute("INSERT INTO user (username, password, email, role) VALUES ('" + params["username"].asString() + "', '" + params["password"].asString() + "', '" + params["email"].asString() + "', 'customer')");
			// 批处理语句小于0  受影响 < 0 --> 执行失败
			if (affected <= 0)		throw runtime_error("用户注册失败");
			Value response;
			response["message"] = "注册成功";
			sendSucess(res, response, 201); 	// 默认200 
		});
	} catch (const exception& e) {
		sendError(res, e.what());
	}
}
void AuthHandler::login(const Request& req, Response& res) {
	try {
		// 解析请求参数
		Value params = parseRequest(req);
		// 做一下校验
		if (!validateParams(params, {"username", "password"})) {
			return sendError(res, "缺少必要参数", 400);		// 返回错误
		}
		withTransaction([&](DBUtil::Transaction& trans) {
			// 登录只需要比对信息
			// 检查信息是否存在
			Value ans = trans.query("SELECT id, password, role FROM users WHERE username = '" + params["username"].asString() + "'");
			// 密码错误或用户名错误
			// 1. 用户名不符标准
			if (ans.empty() || !ans.isArray() || ans.size() == 0) throw runtime_error("密码或用户名错误");
			// 2. 用户名对应相应的密码
			int userId = ans[0]["id"].asInt();
			string dataPassword = ans[0]["password"].asString();
			string role = ans[0]["role"].asString();
			if (params["password"].asString() != dataPassword)	throw runtime_error("密码或用户名错误");
			// 创建会话
			string sessionId = generateSessionId();
			time_t now = time(nullptr);
			Session newSession {
				userId,
				params["username"].asString(),
				role,
				now + 3600 * 24		// 会话周期只有24小时
			};
			// 会话做存储
			activeSessions[sessionId] = newSession;
			// 设置 Cookie
			res.set_header("Set-Cookie", "session_id=" + sessionId + "; Path=/; HttpOnly");
			Value response;
			response["user_id"] = userId;
            response["username"] = params["username"].asString();
            response["role"] = role;
			sendSucess(res, response); 	// 默认200 
		});
	} catch (const exception& e) {
		sendError(res, e.what());
	}
}
// 用户登出处理函数
void AuthHandler::logout(const Request& req, Response& res) {
	// 检查Cookie 获取sessionId
	try {
		auto cookies = req.headers.find("Cookie");
		// 从headers中全部去获取 都不一样的话 set 一个
		if (cookies != req.headers.end()) {
			string sessionId;
			size_t pos = cookies->second.find("session_id=");
			if (pos != string::npos) {
				sessionId = cookies->second.substr(pos + 11);
				size_t endPart = sessionId.find(";");
				if (endPart != string::npos) {
					sessionId = sessionId.substr(0, endPart);
				}
				// 会话存储中移除 该sessionId
			}
		}
		// 客户端的sessionId 和 Cookie 也清除
		/**
		 * 清除 Cookie 的机制
		 * 依据的是Expires的值或者Max-Age是否为负数。
		 * 设置的是过去的时间，浏览器会认为这个 Cookie 已经过期，进而将它从本地存储中删除。
		 * 把Expires设为Unix 时间的起始点，能确保所有遵循标准的浏览器都会认为该 Cookie 已过期，删除它。
		 */
		  
		res.set_header("Set-Cookie", "session_id=; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=/");
		// 给出登出信息
		Value response;
		response["message"] = "登出成功";
		sendSucess(res, response); 
	} catch (const exception& e) {
		sendError(res, e.what());
	}
}
// 认证请求的辅助函数，检查请求是否包含有效的会话ID
bool AuthHandler::authenticateRequest(const Request& req, int& outUserId, string& outRole) {
	auto cookies = req.headers.find("session_id=");
	if (cookies != req.headers.end())		return false;
	string sessionId;
	size_t pos = cookies->second.find("session_id=");
	if (pos == string::npos)	return false;
	sessionId = cookies->second.substr(pos + 11);
	size_t endPart = sessionId.find(';');
	if (endPart != string::npos)		sessionId = sessionId.substr(0, endPart);
	// 查找会话是存在
	auto it = activeSessions.find(sessionId);
	if (it == activeSessions.end()) 	return false;
	// 检查过期
	if (time(nullptr) > it->second.expire_time) {
		activeSessions.erase(it);
		return false;
	}
	// 有效会话 就返回用户ID和role
	outUserId = it->second.user_id;
	outRole = it->second.role;
	return true;
}

AuthHandler::~AuthHandler() = default;


